package com.ecgsystem.panel;

import java.util.concurrent.ConcurrentLinkedQueue;

import com.ecgsystem.activity.OfflineECG;
import com.ecgsystem.constants.Commons;
import com.ecgsystem.constants.Constants;
import com.ecgsystem.thread.ThreadGetSignalByFrame;

import com.ecgsystem.R;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.graphics.Typeface;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ScaleGestureDetector;

/**
 * @author anhtuan
 * 
 */
public class CopyOfPanel6 extends SurfaceView implements
		SurfaceHolder.Callback, Constants {
	/*
	 * 1 o nho 1mm voi toc do 25 mm/s 1mm = 0.04s 1mm = 4px 1s = 100 px tan so
	 * lay mau a(s) lenght = 0.04/a * 62.5 = 2.5 /a khoang cach a * 25 *
	 * PixelPerMm
	 */
	private Paint grid;
	private Paint line;
	private Paint text;
	private Paint borderline;
	private Paint linebase;
	private Bitmap _bitmap;
	private float x[][];
	private float y[][];
	private ConcurrentLinkedQueue<Float> QueueDraw[];
	private ConcurrentLinkedQueue<Float> QueueDraw2[];
	private int i = 0;
	private boolean first = true;

	/**
	 * TODO Put here a description of this field.
	 */
	public static int WIDTH;
	/**
	 * TODO Put here a description of this field.
	 */
	public static int HEIGHT = Commons.HEIGHT;

	/**
	 * TODO Put here a description of this field.
	 */
	public static float baseline[];

	/**
	 * TODO Put here a description of this field.
	 */
	public static float PixelPerMm = (int) (Commons.HEIGHT / 105);

	/**
	 * TODO Put here a description of this field.
	 */
	public static float zoom = 7;

	/**
	 * tan so lay mau f
	 */
	public static float fx = 0.002f; // 0.002s 1 mau
	// toc do giay
	/**
	 * TODO Put here a description of this field.
	 */
	public static float v = 25; // 25mm/s
	// so diem ve tren ca ban
	private int ARRAYLENGHT;

	private static float MIN_ZOOM = 1f;
	private static float MAX_ZOOM = 5f;

	private float scaleFactor = 1.f;
	private ScaleGestureDetector detector;
	private PointF mid;

	private SurfaceHolder _holder;
	private PanelThread _thread = null;

	private int flag = 1;

	/**
	 * TODO Put here a description of what this constructor does.
	 * 
	 * @param context
	 */
	public CopyOfPanel6(final Context context) {
		super(context);

		this.ARRAYLENGHT = Math.round(60 / (v * fx));// co 12 o lon
		this.x = new float[4][this.ARRAYLENGHT * 4];
		this.y = new float[12][this.ARRAYLENGHT];
		baseline = new float[3];

		// mang toa do x

		this.setVisibility(VISIBLE);
		this.setEnabled(true);
		this.setZOrderOnTop(false);

		this.borderline = new Paint();
		this.borderline.setColor(getResources().getColor(R.color.borderline));
		this.borderline.setStrokeWidth(3);

		this.text = new Paint();
		this.text.setColor(Color.RED);
		this.text.setTextSize(14);
		this.text.setTypeface(Typeface.DEFAULT_BOLD);

		this.grid = new Paint();
		this.grid.setColor(getResources().getColor(R.color.grid));
		this.grid.setStrokeWidth(1);

		this.line = new Paint(Paint.ANTI_ALIAS_FLAG);
		this.line.setStyle(Paint.Style.FILL_AND_STROKE);
		this.line.setColor(getResources().getColor(R.color.line));
		this.line.setAntiAlias(true);
		this.line.setStrokeWidth(2f);

		this.linebase = new Paint();
		this.linebase.setColor(Color.GRAY);
		this.linebase.setAntiAlias(true);
		this.linebase.setStrokeWidth(0.5f);

		this.detector = new ScaleGestureDetector(context, new ScaleListener());
		this.mid = new PointF();

		this.getHolder().addCallback(this);
	}

	/**
	 * TODO Put here a description of what this method does.
	 * 
	 * @param QueueDraw
	 */
	public void setQueueDraw(final ConcurrentLinkedQueue<Float> QueueDraw[]) {
		this.QueueDraw = QueueDraw.clone();
		this._holder = getHolder();
		this._holder.addCallback(this);
	}
	
	public ConcurrentLinkedQueue<Float>[] copy(ConcurrentLinkedQueue<Float> QueueDraw[]){
		ConcurrentLinkedQueue<Float>[] q = (ConcurrentLinkedQueue<Float>[]) new ConcurrentLinkedQueue[12];
		Float drawArray[][] = new Float[12][];
		for (int i = 0; i < 12; i++) {
			q[i] = new ConcurrentLinkedQueue<Float>();
			
			drawArray[i] = QueueDraw[i].toArray(new Float[0]);
			for(int j = 0; j< drawArray[i].length; j++){
				q[i].add(drawArray[i][j]);
			}
		}
		return q;
	}

	public void setQueueDraw2() {
		if (this._thread == null || !this._thread.isAlive()) {
			this.QueueDraw2 = copy(QueueDraw);
			this._holder = getHolder();
			this._holder.addCallback(this);
			this.i = 0;
			this.first = true;
			this._thread = new PanelThread(_holder, this._bitmap);
			Log.d("setq", "setq");
			this._thread.start();
		}
	}

	/**
	 * TODO Put here a description of what this method does.
	 * 
	 * @param progress
	 */

	public void startDrawAt(int progress) {
		this.flag = 0;
		Stop();
		Canvas c = null;
		c = this._holder.lockCanvas(null);
		synchronized (this._holder) {
			if (this._bitmap != null && c != null) {
				c.save();
				c.scale(this.scaleFactor, this.scaleFactor, this.mid.x,
						this.mid.y);

				Draw(c, new Canvas(this._bitmap), progress);
				c.restore();
			}
		}
		if (c != null) {
			this._holder.unlockCanvasAndPost(c);
		}
	}

	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		// Let the ScaleGestureDetector inspect all events.
		if (ev.getAction() == 261) {
			float x = (ev.getX(0) + ev.getX(1)) / 2;
			float y = (ev.getY(0) + ev.getY(1)) / 2;
			this.mid.set(x, y);
		}
		this.detector.onTouchEvent(ev);
		return true;
	}

	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		// TODO Auto-generated method stub
		WIDTH = width;// (int) (width * this.scaleFactor);
		HEIGHT = Commons.HEIGHT;
		this._bitmap = Bitmap.createBitmap(WIDTH, HEIGHT,
				Bitmap.Config.ARGB_4444);
		baseline[0] = (float) (17.5 * PixelPerMm);
		baseline[1] = (float) (52.5 * PixelPerMm);
		baseline[2] = (float) (87.5 * PixelPerMm);
		float temp = v * fx * PixelPerMm;
		float width4 = PixelPerMm * 60;
		for (int j = 0; j < this.ARRAYLENGHT; j++) {
			for (int i = 0; i < 4; i++) {
				this.x[i][j] = temp * j + i * width4;
			}
		}

		Canvas c = null;
		try {
			c = holder.lockCanvas(null);
			synchronized (holder) {
				Draw(c, new Canvas(this._bitmap), 0);
				// Draw2(c, new Canvas(this._bitmap));

				c.restore();
			}
		} finally {
			if (c != null) {
				holder.unlockCanvasAndPost(c);
			}
		}

	}

	/**
	 * TODO Put here a description of what this method does.
	 * 
	 * @param vCanvas
	 * @param iCanvas
	 * @param progress
	 */
	public void Draw(final Canvas vCanvas, final Canvas iCanvas,
			final int progress) {
		// TODO Auto-generated method stub
		// V蘯?� l??��盻�?n?�?�?n
		DrawGrid(iCanvas);
		Float drawArray[][] = new Float[12][];
		if (OfflineECG.startDraw) {
			for (int i = 0; i < 12; i++)
				if (ThreadGetSignalByFrame.hasRecord[i]) {
					drawArray[i] = this.QueueDraw[i].toArray(new Float[0]);
					for (int j = 0; j < drawArray[i].length; j++) {
						drawArray[i][j] = this.signalToY(i, drawArray[i][j]);
					}
				}
			int index = 0;
			int startIndex = 0;
			index = 5000 * progress / 100;
			if (index > this.ARRAYLENGHT)
				startIndex = index - this.ARRAYLENGHT;
			else
				startIndex = 0;
			if (index > drawArray[0].length) {
				index = drawArray[0].length;
			}

			if (this.QueueDraw != null && OfflineECG.startDraw == true) {
				for (int no = 0; no < 12; no++)
					if (ThreadGetSignalByFrame.hasRecord[no]) {
						for (int i = 0, j = startIndex; j < index - 1; i++, j++) {
							iCanvas.drawLine(this.x[no / 3][i],
									drawArray[no][j], this.x[no / 3][i + 1],
									drawArray[no][j + 1], this.line);
						}
					}
			}
		}
		if (this._bitmap != null && vCanvas != null)
			vCanvas.drawBitmap(this._bitmap, 0, 0, null);
	}

	private float signalToY(int stt, float signal) {
		float y = 0;
		int i = stt % 3;
		y = baseline[i] - signal * zoom * 10;
		if (y < baseline[i] - HEIGHT / 6) {
			y = baseline[i] - HEIGHT / 6;
		}
		if (y > baseline[i] + HEIGHT / 6) {
			y = baseline[i] + HEIGHT / 6;
		}
		return y;
	}

	private void DrawGrid(Canvas c) {

		this._bitmap.eraseColor(getResources().getColor(R.color.background));
		float t = 0;
		int i = 0;
		Paint draw;
		while (t < WIDTH) {
			if (i % 12 == 0) {
				draw = this.borderline;
			} else {
				draw = this.grid;
			}
			c.drawLine(t, 0, t, HEIGHT, draw);
			t += 5 * PixelPerMm;
			i++;
		}

		// Draw horizontal line
		t = 0;
		i = 0;
		while (t < HEIGHT) {
			if (i % 7 == 0) {
				draw = this.borderline;
			} else {
				draw = this.grid;
			}
			c.drawLine(0, t, WIDTH, t, draw);
			t += 5 * PixelPerMm;
			i++;
		}

		// c.drawText(typeECG, 10, 20, text);
	}

	private class PanelThread extends Thread {
		private SurfaceHolder _surfaceHolder;
		private Bitmap bitmap;
		private boolean _run = false;

		/**
		 * TODO Put here a description of what this constructor does.
		 * 
		 * @param surfaceHolder
		 * @param _bitmap
		 */
		public PanelThread(final SurfaceHolder surfaceHolder,
				final Bitmap _bitmap) {
			this._surfaceHolder = surfaceHolder;
			this.bitmap = _bitmap;
			this._run = true;
		}

		/**
		 * TODO Put here a description of what this method does.
		 * 
		 */
		public void StopRun() {
			// TODO Auto-generated method stub
			this._run = false;
		}

		/**
		 * TODO Put here a description of what this method does.
		 * 
		 * @param run
		 */
		public boolean isRunning() {
			return this._run;
		}

		@Override
		public void run() {
			Canvas c;
			while (this._run) {
				c = null;
				try {
					Thread.sleep(Constants.SLEEPPING_TIME);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				c = this._surfaceHolder.lockCanvas(null);
				synchronized (this._surfaceHolder) {
					if (this.bitmap != null && c != null) {
						c.save();
						// c.scale(Panel6Online.this.scaleFactor,
						// Panel6Online.this.scaleFactor,
						// Panel6Online.this.mid.x, Panel6Online.this.mid.y);
						Log.d("aaaa", "aaaa");
						Draw2(c, new Canvas(this.bitmap));
						c.restore();
					}
				}
				if (c != null) {
					this._surfaceHolder.unlockCanvasAndPost(c);
				}
			}
		}
	}

	public void Draw2(Canvas vCanvas, Canvas iCanvas) {
		// TODO Auto-generated method stub
		// V蘯?� l??��盻�?n?�?�?n
		if (first) {
			DrawGrid(iCanvas);
		}
		int tempi = this.i;

		if (QueueDraw2 != null
				&& this.QueueDraw2[0].size() >= Constants.NUM_OF_SIGNAL_DRAWED) {
			for (int no = 0; no < 12; no++)
				if (ThreadGetSignalByFrame.hasRecord[no]) {
					tempi = this.i;
					for (int j = 0; j < Constants.NUM_OF_SIGNAL_DRAWED
							&& tempi <= this.ARRAYLENGHT - 1; j++, tempi++) {
						this.y[no][tempi] = getSignal(no);
					}
					// V??��ng l蘯?�p v蘯?� li??��n ti蘯?�p n盻訴 i ??��盻�?
					int j;
					if (this.i == 0)
						j = 0;
					else
						j = this.i - 1;
					for (; j < tempi - 1; j++) {
						iCanvas.drawLine(this.x[no / 3][j], this.y[no][j],
								this.x[no / 3][j + 1], this.y[no][j + 1],
								this.line);
					}
				}
			if (tempi < this.ARRAYLENGHT - 1) {
				this.i = tempi;
				this.first = false;
			}
			// v蘯?� l蘯?�i t盻?� ??��ｺ?�u khi ??��?� v蘯?� h蘯?�t khung h??��nh
			else {
				this.i = 0;
				this.first = true;
			}
		} else {
			Stop();
		}
		if (this._bitmap != null && vCanvas != null)
			vCanvas.drawBitmap(this._bitmap, 0, 0, null);
	}

	private float getSignal(int stt) {
		int i = stt % 3;
		if (this.QueueDraw2[stt] != null && !this.QueueDraw2[stt].isEmpty()) {
			float signal = baseline[i]
					- this.QueueDraw2[stt].remove().floatValue() * zoom * 10;
			if (signal < baseline[i] - HEIGHT / 6) {
				signal = baseline[i] - HEIGHT / 6;
			}
			if (signal > baseline[i] + HEIGHT / 6) {
				signal = baseline[i] + HEIGHT / 6;
			}
			return signal;
		} else {
			Stop();
			return -1;
		}
	}

	public void Stop() {
		if (this._thread != null && this._thread.isAlive()) {
			Log.d("Stop online drawing", "aa");
			this._thread.StopRun();
			this._thread = null;
		}
	}

	private class ScaleListener extends
			ScaleGestureDetector.SimpleOnScaleGestureListener {
		@Override
		public boolean onScale(ScaleGestureDetector detector) {
			CopyOfPanel6.this.scaleFactor *= detector.getScaleFactor();
			CopyOfPanel6.this.scaleFactor = Math.max(MIN_ZOOM,
					Math.min(CopyOfPanel6.this.scaleFactor, MAX_ZOOM));
			invalidate();
			return true;
		}
	}

	public void surfaceCreated(SurfaceHolder arg0) {
		// TODO Auto-generated method stub.

	}

	public void surfaceDestroyed(SurfaceHolder holder) {
		if (this._thread != null && this._thread.isAlive()) {
			this._thread.StopRun();
		}
	}
}